package data.platform.common.merge;

import data.platform.common.util.DateUtil;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

@Getter
@Setter
@NoArgsConstructor
public class FaultAggregateItem extends AggregateItem {

    private boolean faultStatus = false;

    // 故障次数
    private int faultCount = 0;

    // 正常次数
    private int nonFaultCount = 0;

    // 已结束的故障时长
    private long faultedTime = 0;

    // 故障未结束时长 这里计算的原因是防止窗口结束时，故障还未结束
    private long faultingTime = 0;

    // 故障时长
    private long faultTime = 0;

    // 平均故障时长
    private long mttr = 0;

    // 平均无故障时长
    private long mttf = 0;

    // 平均故障间隔时长 mttr+mttf
    private long mtbf = 0;

    // 运行率 单位%
    private double runRate = 0;

    private Long latestValue;

    private LocalDateTime latestEventTime;

    // 故障时段 - 减少内存使用，只记录当前没有结束的故障时段
    private FaultSpan faultSpan;

    public FaultAggregateItem(MergePeriod mergePeriod, MergeTimeWindow mergeTimeWindow) {
        super(mergePeriod, mergeTimeWindow);
    }

    @Override
    public void compute(Double value, LocalDateTime eventTime) {
        Long currentValue = value.longValue();
        if (currentValue == 0 && faultStatus == false) {
            // 故障发生
            faultStatus = true;
            faultCount++;
            faultSpan = new FaultSpan();
            faultSpan.setStartTime(eventTime);
        } else if (currentValue > 0 && faultStatus == true) {
            // 故障结束
            faultStatus = false;
            nonFaultCount++;
            faultSpan.setEndTime(eventTime);
            this.faultedTime += faultSpan.getStartTime().until(faultSpan.getEndTime(), ChronoUnit.MILLIS);
        } else if (currentValue > 0 && faultStatus == false && nonFaultCount == 0) {
            // 第一次获取的数据是正常状态，正常状态次数设置为1
            nonFaultCount++;
        }

        latestValue = currentValue;
        latestEventTime = eventTime;

        dirty.compareAndSet(false, true);
    }

    // 统计的时候调用方法进行值计算
    public void windowEndCompute() {
        if (faultStatus == true) {
            this.faultingTime = mergeTimeWindow.getEndTime() - DateUtil.getDateOfLocalDateTime(faultSpan.getStartTime()).getTime();
        }

        this.faultTime = this.faultedTime + this.faultingTime;

        // 总的统计时间周期时长
        long statisticalSpan = mergeTimeWindow.getEndTime() - mergeTimeWindow.getStartTime();
        // 运行率
        runRate = ((double) (statisticalSpan - faultTime) / statisticalSpan) * 100;
        // 平均故障中断时长 故障总时长/故障总次数
        if (faultTime != 0) {
            mttr = faultCount == 0 ? 0 : faultCount / faultTime;
        }
        // 平均无故障时长 总的无故障时长/无故障总数次
        if (nonFaultCount != 0) {
            mttf = (statisticalSpan - faultTime) / nonFaultCount;
        }
        mtbf = mttr + mttf;
    }

}
